package de.szut.sudoku.gui;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Observable;

import de.szut.sudoku.game.field.FieldGroup;
import de.szut.sudoku.game.field.Box;

import javax.swing.JFrame;

import de.szut.internalorganizer.InternalSaver;
import de.szut.sudoku.game.GameModelActions;
import de.szut.sudoku.game.GameModelAction;
import de.szut.sudoku.game.field.SudokuField;
import de.szut.sudoku.gui.sudokufield.SudokuFieldGenerator;
import de.szut.sudoku.main.GameController;
import de.szut.sudoku.main.UserInterface;

/**
 * MainFrame of the GUI, contains pretty much the entire frame
 * 
 * @author dqi12huisinga
 * 
 */
@SuppressWarnings("serial")
public class MainFrame extends JFrame implements UserInterface {
	private static MainFrame frame;
	private LanguageContainer lContainer;
	private SudokuPanel sudokuPanel;

	public SudokuPanel getSudokuPanel() {
		return sudokuPanel;
	}

	public void setSudokuPanel(SudokuPanel sudokuPanel) {
		this.sudokuPanel = sudokuPanel;
	}

	private ExitOperator exitOperator;

	public final static String frameTitle = "Sudoku";

	public final static int WIDTH = 2 * SudokuFieldGenerator.STARTINGPOSITIONX
			+ SudokuFieldGenerator.getSudokuFieldWidth() - 5;
	public final static int HEIGHT = 2 * SudokuFieldGenerator.STARTINGPOSITIONY
			+ SudokuFieldGenerator.getSudokuFieldHeight();

	public ExitOperator getExitOperator() {
		return exitOperator;
	}

	public void setExitOperator(ExitOperator exitOperator) {
		this.exitOperator = exitOperator;
	}

	public LanguageContainer getlContainer() {
		return lContainer;
	}

	public void setlContainer(LanguageContainer lContainer) {
		this.lContainer = lContainer;
	}

	/**
	 * Singleton of the MainFrame
	 * 
	 * @return
	 */
	public static MainFrame getInstance() {
		if (frame == null) {
			frame = new MainFrame();
		}
		return frame;
	}

	private MainFrame() {
		exitOperator = new ExitOperator();
		lContainer = new LanguageContainer();
		lContainer.setFilePathPrefix("data/gui/language/");
		lContainer.setCurrentLanguage(GameController.getInstance()
				.getConfiguration().getProperty("game.language"));
	}

	/**
	 * updates the GUI
	 */
	@Override
	public void update(Observable arg0, Object arg1) {
		GameModelAction action = (GameModelAction) arg1;
		// changes the value on the field
		if (action.getState() == GameModelActions.CHANGEVALUE) {
			sudokuPanel.getSudokuField().getSudokuButtons()[action
					.getSudokuButtonChanger().getyPosition()][action
					.getSudokuButtonChanger().getxPosition()]
					.setSudokuText(Integer.toString(action
							.getSudokuButtonChanger().getChangedValue()));
			// generates a new visual field
		} else if (action.getState() == GameModelActions.GENERATEFIELD) {
			sudokuPanel.getSudokuField().loadFieldIntoVisuals(
					action.getSudokuFieldContainer().getCurrentField());
			// sets the position and ends the game
		} else if (action.getState() == GameModelActions.ENDGAME) {
			sudokuPanel.getSudokuField().getSudokuButtons()[action
					.getSudokuButtonChanger().getyPosition()][action
					.getSudokuButtonChanger().getxPosition()]
					.setSudokuText(Integer.toString(action
							.getSudokuButtonChanger().getChangedValue()));
			new GameEndedFrame();
			// saves the game
		} else if (action.getState() == GameModelActions.SAVEGAME) {
			saveSudokuPanel(action.getSudokuFieldContainer().getLocation(),
					action.getSudokuFieldContainer().getCurrentField(), action
							.getSudokuFieldContainer().getGoalField(), action
							.getSudokuFieldContainer().getStartField());
			// loads a game
		} else if (action.getState() == GameModelActions.LOADGAME) {
			// loads the start field into the visuals
			sudokuPanel.getSudokuField().loadFieldIntoVisuals(
					action.getSudokuFieldContainer().getStartField());
			// adds the fields the user changed into the visuals
			sudokuPanel.getSudokuField().addFieldIntoVisuals(
					SudokuField.getXORdField(action.getSudokuFieldContainer()
							.getCurrentField(), action
							.getSudokuFieldContainer().getStartField()));
			// resets the timer and starts the game
			resetTimer();
			sudokuPanel.setGameHasStarted(true);
			sudokuPanel.showVisualField();
		}

	}

	/**
	 * Saves the sudokufield
	 * 
	 * @param location
	 * @param currentField
	 * @param goalField
	 * @param startField
	 */
	public void saveSudokuPanel(String location, SudokuField currentField,
			SudokuField goalField, SudokuField startField) {
		InternalSaver saver = new InternalSaver();
		// converts all 3 fields into 2D String arrays
		// current field
		String[][] field1 = new String[9][9];
		int xIndex = 0;
		for (FieldGroup horizontal : currentField.getHorizontalGroups()) {
			int yIndex = 0;
			for (Box currentBox : horizontal.getBoxes()) {
				field1[xIndex][yIndex] = Integer
						.toString(currentBox.getState());
				yIndex++;
			}
			xIndex++;
		}
		// goal field
		String[][] field2 = new String[9][9];
		xIndex = 0;
		for (FieldGroup horizontal : goalField.getHorizontalGroups()) {
			int yIndex = 0;
			for (Box currentBox : horizontal.getBoxes()) {
				field2[xIndex][yIndex] = Integer
						.toString(currentBox.getState());
				yIndex++;
			}
			xIndex++;
		}

		// start field
		String[][] field3 = new String[9][9];
		xIndex = 0;
		for (FieldGroup horizontal : startField.getHorizontalGroups()) {
			int yIndex = 0;
			for (Box currentBox : horizontal.getBoxes()) {
				field3[xIndex][yIndex] = Integer
						.toString(currentBox.getState());
				yIndex++;
			}
			xIndex++;
		}

		// saves the data
		saver.setFile(new File(location));

		try {
			saver.saveData(location, "Sudoku", field1, field2, field3);
		} catch (IOException e) {
			System.out.println("Saving failed");
			e.printStackTrace();
		}
	}

	/**
	 * Starts the GUI
	 */
	@Override
	public void startUI() {
		setTitle(frameTitle);
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		// adds a window listener to trigger the exit operation upon pressing
		// the frame-exit
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				exitOperator.callExitOperation();
			}
		});
		setBounds(100, 100, WIDTH, HEIGHT);
		setVisible(true);
		sudokuPanel = new SudokuPanel();
		setContentPane(sudokuPanel);
		setResizable(false);
		// loads the language
		try {
			lContainer.translate();
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(0);
		}

	}

	/**
	 * Resets the field
	 */
	public void resetField() {
		// clears the field
		sudokuPanel.getSudokuField().clearSudokuField();
		// refreshes the translation
		try {
			lContainer.translate();
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(0);
		}
		// starts the game
		sudokuPanel.getBtnStart().setVisible(true);
		sudokuPanel.setGameHasStarted(false);
		resetTimer();
	}

	private void resetTimer() {
		sudokuPanel.getTimer().restart();
		sudokuPanel.getTimer().stop();
		sudokuPanel.setCurrentSudokuTime(0);
		sudokuPanel.getLblTimer().setText("0s");
		sudokuPanel.getLblTimer().setVisible(false);
	}

}
